//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Microsoft.IdentityModel.Xml;
using static Microsoft.IdentityModel.Logging.LogHelper;

namespace Microsoft.IdentityModel.Tokens.Saml
{
    /// <summary>
    /// Represents the Assertion element specified in [Saml, 2.3.2].
    /// </summary>
    public class SamlAssertion
    {
        private string _assertionId;
        private string _issuer;
        private DateTime _issueInstant;

        /// <summary>
        /// Creates an instance of <see cref="SamlAssertion"/>.
        /// </summary>
        /// <param name="assertionId">AssertionID of the assertion.</param>
        /// <param name="issuer">Issuer of the assertion.</param>
        /// <param name="issueInstant">IssueInstant of the assertion.</param>
        /// <param name="samlConditions">SamlConditions of the assertion.</param>
        /// <param name="samlAdvice">SamlAdvice of the assertion.</param>
        /// <param name="samlStatements"><see cref="IEnumerable{SamlStatement}"/>.</param>
        public SamlAssertion(
            string assertionId,
            string issuer,
            DateTime issueInstant,
            SamlConditions samlConditions,
            SamlAdvice samlAdvice,
            IEnumerable<SamlStatement> samlStatements
            )
        {
            Statements = (samlStatements == null) ? throw LogArgumentNullException(nameof(samlStatements)) : new List<SamlStatement>(samlStatements);

            AssertionId = assertionId;
            Issuer = issuer;
            IssueInstant = issueInstant;
            Conditions = samlConditions;
            Advice = samlAdvice;
        }

        /// <summary>
        /// Gets or sets additional information related to the assertion that assists processing in certain
        /// situations but which may be ignored by applications that do not understand the
        /// advice or do not wish to make use of it.
        /// </summary>
        public SamlAdvice Advice { get; set; }

        /// <summary>
        /// Gets or sets the identifier for this assertion.
        /// </summary>
        public string AssertionId
        {
            get { return _assertionId; }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw LogArgumentNullException(nameof(value));

                _assertionId = value;
            }
        }

        /// <summary>
        /// Gets or sets conditions that must be evaluated when assessing the validity of and/or
        /// when using the assertion.
        /// </summary>
        public SamlConditions Conditions { get; set; }

        /// <summary>
        /// Gets or sets the a PrefixList to use when there is a need to include InclusiveNamespaces writing token.
        /// </summary>
        public string InclusiveNamespacesPrefixList { get; set; }

        /// <summary>
        /// Gets or sets the issuer in the assertion.
        /// </summary>
        public string Issuer
        {
            get { return _issuer; }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw LogArgumentNullException(nameof(value));

                _issuer = value;
            }
        }

        /// <summary>
        /// Gets or sets the time instant of issue in UTC.
        /// </summary>
        public DateTime IssueInstant
        {
            get { return _issueInstant; }
            set { _issueInstant = DateTimeUtil.ToUniversalTime(value); }
        }

        /// <summary>
        /// Gets the major version of this assertion. [Saml, 2.3.2]
        /// <remarks>
        /// The identifier for the version of SAML defined in this specification is 1.
        /// </remarks>
        /// </summary>
        public string MajorVersion
        {
            get { return SamlConstants.MajorVersionValue; }
        }

        /// <summary>
        /// Gets the minor version of this assertion. [Saml, 2.3.2]
        /// <remarks>
        /// The identifier for the version of SAML defined in this specification is 1.
        /// </remarks>
        /// </summary>
        public string MinorVersion
        {
            get { return SamlConstants.MinorVersionValue; }
        }

        /// <summary>
        /// Gets or sets the <see cref="Signature"/> on the Assertion.
        /// </summary>
        public Signature Signature { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="SigningCredentials"/> used by the issuer to protect the integrity of the assertion.
        /// </summary>
        public SigningCredentials SigningCredentials { get; set; }

        /// <summary>
        /// Gets the <see cref="IList{SamlStatement}"/>(s) regarding the subject.
        /// </summary>
        public IList<SamlStatement> Statements { get; }
    }
}
